import cmath
import numpy as np

import matplotlib.pyplot as plt
import math
class FFT():
    def __init__(self,input):
        self.createFFT(input)
    def createFFT(self,input):
        self.inputList=input
        self.mfft()
        self.arrayAbs()
        self.arrayArg()

    def W(self,N, n, k):
        O = 2 * np.pi / N * n * k
        z = 1.0j
        return cmath.exp(O * z)

    def to2L(self):
        input=self.inputList.copy()
        m = int(math.log(len(input)) / math.log(2))
        n = math.log(len(input)) / math.log(2)
        if m == n:
            pass
        else:
            m = m + 1
        length = math.pow(2, m)
        for i in range(len(input), int(length)):
            input.append(0)
        self.FFTList=input

    def sortReverse(self):
        sorted = []
        for i in range(0, len(self.FFTList)):
            if i in sorted:
                pass
            else:
                temp = i
                rei = 0
                n = int(math.log(len(self.FFTList)) / math.log(2))
                for count in range(0, n - 1):
                    order = temp % 2
                    rei += order
                    rei = rei << 1
                    temp = int(temp / 2)
                rei += temp % 2
                if rei != i:
                    self.FFTList[i], self.FFTList[rei] = self.FFTList[rei], self.FFTList[i]
                    sorted.append(i)
                    sorted.append(rei)

    def mfft(self):
        self.to2L()
        self.sortReverse()
        step = 1
        while (step != len(self.FFTList)):
            for i in range(0, len(self.FFTList) - step, 2 * step):
                for l in range(0, step):
                    tempLow =self.FFTList[i + l] + self.W(2 * step, 1, l) *self.FFTList[i + l + step]
                    tempHigh = self.FFTList[i + l] - self.W(2 * step, 1, l) * self.FFTList[i + l + step]
                    self.FFTList[i + l] = tempLow
                    self.FFTList[i + l + step] = tempHigh
            step *= 2
#print(W(4,2,1))
    #pass
    def arrayAbs(self):
        input=self.FFTList.copy()
        for i in range(0, len(self.FFTList)):
            input[i] = abs(self.FFTList[i])
        self.AltitudeResponse=input
    def arrayArg(self):
        input = self.FFTList.copy()
        for i in range(0, len(self.FFTList)):
            input[i] = math.atan(self.FFTList[i].imag/self.FFTList[i].real)
        self.ArgResponse=input
    def plot(self):
        fig, ax = plt.subplots(2, 1, sharex=True)
        ax[0].plot(range(0, len(self.AltitudeResponse)), self.AltitudeResponse)
        ax[0].set_title("AtitudeResponseImg")
        ax[1].plot(range(0, len(self.ArgResponse)), self.ArgResponse)
        ax[1].set_title("ArgResponseImg")
        plt.show()
